//
//  MFWServiceModel.m
//  MFWSdk
//
//  Created by Song Xiaofeng on 13-8-1.
//  Copyright (c) 2013年 Mafengwo Inc. All rights reserved.
//

#import "MFWServiceModel.h"

@implementation MFWServiceModel
- (id)init
{
    self = [super init];
    if (self)
    {
        _dataStatusDic = [NSMutableDictionary dictionaryWithCapacity:7];
    }
    return self;
}

- (BOOL)bSupportPersistentCache:(NSString*)dataId
{
    return NO;
}

- (MFWJson*)jsonDataForDataId:(NSString*)dataId;
{
    id data = [_dataDic objectForKey:dataId];
    
    if (data == nil || ([data respondsToSelector:@selector(count)] && [data count] == 0))
    {    
        if ([self bSupportPersistentCache:dataId])
        {
            NSDate *cacheDate = nil;
            MFWJson *json = [self _loadCacheDataForDataId:dataId cacehDate:&cacheDate];
            
            if ([self processCacheData:json forDataId:dataId])
            {
//                [_dataDic setValue:json.jsonObj forKey:dataId];
//                [self processServiceSuccRawData:nil parsedJson:json forTask:nil];
                MFWDataStatus *dataStatus = [[MFWDataStatus alloc] init];
                dataStatus.statusType = kDataStatus_CacheData;
                dataStatus.refreshDate = cacheDate;
                [_dataStatusDic setValue:dataStatus forKey:dataId];
                
                return json;
            }//~ end if
            else
            {// no cache data has been cached
                
            }
        }//~ end if

        data = [NSMutableDictionary dictionaryWithCapacity:10];
        [_dataDic setValue:data forKey:dataId];
    }
    return [MFWJson jsonWithObject:data];
}

/**
 *	业务数据接口返回的json数据中列表型数据的key
 *  default return @"list"
 *
 *	@return	key string in json object
 */
- (NSString*)keyOfListData;
{
    return @"list";
}

/**
 *	列表型json数据，该数据是json array, 是@selector(keyOfListData)返回的key对应的value
 *
 *	@param	dataId	model中的dataId
 *
 *	@return	json array
 */
- (MFWJson*)listJsonForDataId:(NSString*)dataId;
{
    MFWJson *dataJson = [self jsonDataForDataId:dataId];
    NSString *listKey = [self keyOfListData];
    MFWJson *listJson = [dataJson jsonForKey:listKey];
    if (listJson == nil)
    {
        [dataJson.jsonObj setValue:[NSMutableArray array] forKey:listKey];
        listJson = [dataJson jsonForKey:listKey];
    }
    else
    {
        if ([listJson.jsonObj isKindOfClass:[NSArray class]] && ![listJson.jsonObj respondsToSelector:@selector(removeObjectsInArray:)]) {
            NSMutableArray *mutableArray = [listJson.jsonObj mutableCopy];
            [dataJson.jsonObj setValue:mutableArray forKey:listKey];
//            listJson = [MFWJson jsonWithObject:mutableArray];
            listJson = [dataJson jsonForKey:listKey];
        }
    }
    
    if (listJson.jsonObj)
    {
        NSAssert([listJson.jsonObj isKindOfClass:[NSArray class]], @"listJson NOT JSON ARRAY ->%@", listJson);
    }
    
    return listJson;
}
/**
 *	@see [self listJsonForDataId:mfwDefaultDataId]
 *
 *	@return	json array
 */
- (MFWJson*)listJson;
{
    return [self listJsonForDataId:mfwDefaultDataId];
}

- (MFWDataStatus *)_loadDataSatusWithCacheDataForDataId:(NSString*)dataId
{
    // maybe geneate cache data status
    [self jsonDataForDataId:dataId];
    
    // try to fetch cache data status, if load cache data successfully this value must not be nil
    MFWDataStatus *cacheStatus = [_dataStatusDic objectForKey:dataId];
    return cacheStatus;
}

- (MFWDataStatus*)dataStatusForDataId:(NSString*)dataId;
{
    MFWDataStatus *dataStatus = nil;
    dataStatus = [_dataStatusDic objectForKey:dataId];

    if (!dataStatus)
    {
        dataStatus = [[MFWDataStatus alloc] init];
        
        if ([self bSupportPersistentCache:dataId])
        {
            MFWDataStatus *cacheStatus = [self _loadDataSatusWithCacheDataForDataId:dataId];
            if (cacheStatus)
            {
                return cacheStatus;
            }
        }

        [_dataStatusDic setValue:dataStatus forKey:dataId];

    }
    
    return dataStatus;
}

- (BOOL)appendListItem:(id)item forDataId:(NSString*)dataId;
{
    if (item &&
         ([item isKindOfClass:[NSArray class]] || [item isKindOfClass:[NSDictionary class]]))
    {
        NSMutableArray *listArray = [self listJsonForDataId:dataId].jsonObj;
        if ([listArray isKindOfClass:[NSMutableArray class]])
        {
            [listArray addObject:item];
            return YES;
        }
        else
        {
            NSAssert(NO, @"Attempt to add an object to a unmutable collection!");
        }
    }
    
    return NO;
}

- (BOOL)insertAheadListOriginItem:(id)item forDataId:(NSString*)dataId;
{
    if (item &&
        ([item isKindOfClass:[NSArray class]] || [item isKindOfClass:[NSDictionary class]]))
    {
        NSMutableArray *listArray = [self listJsonForDataId:dataId].jsonObj;
        if ([listArray isKindOfClass:[NSMutableArray class]])
        {
            [listArray insertObject:item atIndex:0];
            return YES;
        }
        else
        {
            DLog(@"listArray type is %@", NSStringFromClass(listArray.class));
            NSAssert(NO, @"Attempt to add an object to a unmutable collection!");
        }
    }
    
    return NO;
}

- (void)removeListItemAntIndexSet:(NSMutableIndexSet*)indexSet forDataId:(NSString*)dataId
{
    if (indexSet && dataId)
    {
        NSMutableArray *listArray = [self listJsonForDataId:dataId].jsonObj;
        if ([listArray isKindOfClass:[NSMutableArray class]])
        {
            [listArray removeObjectsAtIndexes:indexSet];
        }
        else
        {
            NSAssert(NO, @"Attempt to delete objects from a unmutable collection!");
        }
    }
}
- (void)removeListItemForDataId:(NSString*)dataId
{
    if (dataId) {
        NSMutableArray *listArray = [self listJsonForDataId:dataId].jsonObj;
        if ([listArray isKindOfClass:[NSMutableArray class]])
        {
            [listArray removeAllObjects];
        }
        else
        {
            NSAssert(NO, @"Attempt to delete objects from a unmutable collection!");
        }
    }
}

#pragma mark -
- (BOOL)processSuccRawData:(NSData *)rawData parsedJson:(MFWJson *)jsonObj forTask:(MFWHttpTask *)task
{
    BOOL ret = NO;
    if ([jsonObj intValueForKey:@"rc"]== 0 && jsonObj)
    {
        ret = [self processServiceSuccRawData:rawData parsedJson:[jsonObj jsonForKey:@"data"] forTask:task];
    }
    
    if (ret)
    {
        //设置dataStatus
        NSString *dataId = task.dataIdentifier.dataId;
        MFWDataStatus *dataStatus = [self dataStatusForDataId:dataId];
        
        if (task.dataRequestType == kMFWDataRequest_Refresh)
        {// refresh
            dataStatus.refreshDate = [NSDate date];
            dataStatus.statusType = kDataStatus_SuccRefresh;
        }
        else
        {// get more
            dataStatus.statusType = kDataStatus_SuccGetmore;
            
            MFWJson *jsonData = [jsonObj jsonForKey:@"data"];
            NSString *keyOfList = [self keyOfListData];
            if (![MFWStringUtils isEmptyString:keyOfList])
            {
                if ([[jsonData jsonForKey:keyOfList] count] == 0)
                {
                    dataStatus.statusType = kDataStatus_DataEnd;
                }
            }
        }
    }
    // 处理完业务逻辑（解析存储业务数据及其他）后，做持久缓存
    if (ret && [self bSupportPersistentCache:task.dataIdentifier.dataId])
    {
        [self _processPersistentCacheRawData:rawData parsedJson:[jsonObj jsonForKey:@"data"] forTask:task];
    }
    
    return ret;
}


- (void)processFailRawData:(NSData *)rawData parsedJson:(MFWJson *)jsonObj forTask:(MFWHttpTask *)task
{
    //设置dataStatus
    NSString *dataId = task.dataIdentifier.dataId;
    MFWDataStatus *dataStatus = [self dataStatusForDataId:dataId];
    
    if (task.dataRequestType == kMFWDataRequest_Refresh)
    {
        dataStatus.statusType = kDataStatus_ErrorRefresh;
    }
    else
    {
        dataStatus.statusType = kDataStatus_ErrorGetmore;
    }
}

/**
 *	default return NO, sub-class should overide to deal with his own service
 *
 *	@param	rawData	http response raw data
 *	@param	jsonObj	"data" json object of http response pased json object
 *	@param	task	http task
 *
 *	@return	deal service sucessfully or not
 */
- (BOOL)processServiceSuccRawData:(NSData*)rawData parsedJson:(MFWJson*)jsonObj forTask:(MFWHttpTask*)task
{
    NSString *dataId = task.dataIdentifier.dataId;
    NSString *listKey = [self keyOfListData];

    if ([MFWStringUtils isEmptyString:listKey])
    {//非列表型数据
        [_dataDic setValue:jsonObj.jsonObj forKey:dataId];
    }
    else if ([jsonObj hasValueForKey:listKey])
    {//列表型数据
        if (task.dataRequestType == kMFWDataRequest_Refresh)
        {// refresh
            [_dataDic setValue:jsonObj.jsonObj forKey:dataId];
        }
        else if(task.dataRequestType == kMFWDataREquest_GetMore)
        {// get more
           
            //合并list数据
            NSMutableArray *listArray = [self listJsonForDataId:dataId].jsonObj;
            if ([listArray isKindOfClass:[NSMutableArray class]])
            {
                NSArray *newArrayData = [jsonObj jsonForKey:listKey].jsonObj;
                [listArray addObjectsFromArray:newArrayData];
            }
            
        }
    }
    //合并"data"下除了"list"的数据
    NSDictionary *responseData = jsonObj.jsonObj;
    NSMutableDictionary *targetData = [self jsonDataForDataId:dataId].jsonObj;
    if ([targetData respondsToSelector:@selector(setObject:forKey:)])
    {
        if(responseData.count > 0) {
        [responseData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            if (![key isEqualToString:listKey])
            {
                [targetData setObject:obj forKey:key];
            }
        }];
        }
    }
    return YES;
}

- (BOOL)processCacheData:(MFWJson*)cacheData forDataId:(NSString*)dataId;
{
    if (cacheData && dataId)
    {
        [_dataDic setValue:cacheData.jsonObj forKey:dataId];
        return YES;
    }
    return NO;
}

#pragma mark - 
- (BOOL)canGetMoreForDataId:(NSString*)dataId;
{
    return YES;
}

#pragma mark - internal package functions
/**
 *	deal with data-caching, the json data is the concrete service related data
 *  This function called after @selector(processSuccRawData:parsedJson:forTask:).
 *  Sub-class could override it to implements its' own service appeal.
 *
 *	@param	rawData http response raw data
 *	@param	jsonObj concrete service data (the json value of key "data")
 *	@param	task    http request task, involves data id and other request informations
 */
- (void)_processPersistentCacheRawData:(NSData*)rawData parsedJson:(MFWJson*)jsonObj forTask:(MFWHttpTask*)task
{
    //do nothing
}

/**
 *	this methods will auto called when [self jsonDataForDataId:dataId] returns nil and [self bSupportPersistentCache]
 *  returns YES
 *
 *	@param	dataId	dataId
 *
 *	@return	parsed json object from persistent storage data
 */
- (MFWJson*)_loadCacheDataForDataId:(NSString*)dataId cacehDate:(NSDate**)pDate
{
    return nil;
}
@end
